#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
主题: 读写二进制数组数据
问题: 你想读写一个二进制数组的结构化数据到Python元组中。
提示 : 
"""

from struct import Struct
from collections import namedtuple

Record = namedtuple('Record', ['kind', 'x', 'y'])

filename = '11_rw_barray.bin'


def recipe1():
    records = [(1, 2.3, 4.5),
               (6, 7.8, 9.0),
               (12, 13.4, 56.7)]
    with open(filename, 'wb') as f:
        write_records(records, '<idd', f)


def recipe2():
    with open(filename, 'rb') as f:
        for rec in read_records('<idd', f):
            print(f"{rec = }")


def recipe3():
    with open(filename, 'rb') as f:
        data = f.read()
        for rec in unpack_records('<idd', data):
            print(f"{rec = }")


def recipe4():
    with open(filename, 'rb') as f:
        records = (Record(*r) for r in read_records('<idd', f))

        for kind, x, y in records:
            print(f"{kind, x, y = }")

def recipe5():
    '''处理大量的二进制数据'''
    import numpy as np
    f = open(filename, 'rb')
    records = np.fromfile(f, dtype='<i,<d,<d')
    print(f"{records= }")
    print(f"{records[0]= }")
    print(f"{records[1]= }")

def unpack_records(format, data):
    '''整个文件一次性读取到一个字节字符串中，然后在分片解析'''
    record_struct = Struct(format)
    return (record_struct.unpack_from(data, offset) for offset in range(0, len(data), record_struct.size))


def read_records(format, f):
    '''以块的形式增量读取文件'''
    record_struct = Struct(format)
    chunks = iter(lambda: f.read(record_struct.size), b'')
    return (record_struct.unpack(chunk) for chunk in chunks)


def write_records(records, format, f):
    '''
    Write a sequence of tuples to a binary file of structures.
    '''

    record_struct = Struct(format)
    for r in records:
        f.write(record_struct.pack(*r))


def main():
    print('recipe1'.center(20, '*'))
    recipe1()
    print('recipe2'.center(20, '*'))
    recipe2()
    print('recipe3'.center(20, '*'))
    recipe3()
    print('recipe4'.center(20, '*'))
    recipe4()
    print('recipe5'.center(20, '*'))
    recipe5()

if __name__ == '__main__':
    main()
